home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / nrcmd.c < prev    next >
C/C++ Source or Header  |  1993-11-27  |  41KB  |  1,682 lines

  1. /* net/rom user command processing
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5. /* Mods by G1EMM, PA0GRI and WG7J */
  6.  
  7. #include <stdio.h>
  8. #include <ctype.h>
  9. #include <time.h>
  10. #include <dos.h>
  11. #include "config.h"
  12. #include "global.h"
  13. #include "mbuf.h"
  14. #include "ax25.h"
  15. #include "mailbox.h"
  16. #include "netrom.h"
  17. #include "nr4.h"
  18. #include "timer.h"
  19. #include "iface.h"
  20. #include "pktdrvr.h"
  21. #include "lapb.h"
  22. #include "cmdparse.h"
  23. #include "session.h"
  24. #include "socket.h"
  25. #include "commands.h"
  26. #include "files.h"
  27.  
  28. int Nr_hidden = 1;
  29. unsigned Nr_sorttype = 1;
  30. char Nr4user[AXALEN];
  31.  
  32. char *Nr4states[] = {
  33.     "Disconnected",
  34.     "Conn Pending",
  35.     "Connected",
  36.     "Disc Pending",
  37.     "Listening"
  38. } ;
  39.  
  40. char *Nr4reasons[] = {
  41.     "Normal",
  42.     "By Peer",
  43.     "Timeout",
  44.     "Reset",
  45.     "Refused"
  46. } ;
  47. static int dobcnodes __ARGS((int argc,char *argv[],void *p));
  48. static int dobcpoll __ARGS((int argc,char *argv[],void *p));
  49. static int dointerface __ARGS((int argc,char *argv[],void *p));
  50. static int donfadd __ARGS((int argc,char *argv[],void *p));
  51. static int donfdrop __ARGS((int argc,char *argv[],void *p));
  52. static int donfdump __ARGS((void));
  53. static int donfmode __ARGS((int argc,char *argv[],void *p));
  54. static int donodefilter __ARGS((int argc,char *argv[],void *p));
  55. static int donodetimer __ARGS((int argc,char *argv[],void *p));
  56. static int donralias __ARGS((int argc,char *argv[],void *p));
  57. static int donracktime __ARGS((int argc,char *argv[],void *p));
  58. static int donrmycall __ARGS((int argc,char *argv[],void *p));
  59. static int donrchoketime __ARGS((int argc,char *argv[],void *p));
  60. static int donrconnect __ARGS((int argc,char *argv[],void *p));
  61. static int donrirtt __ARGS((int argc,char *argv[],void *p));
  62. static int donrkick __ARGS((int argc,char *argv[],void *p));
  63. static int dorouteadd __ARGS((int argc,char *argv[],void *p));
  64. static int doroutedrop __ARGS((int argc,char *argv[],void *p));
  65. static int donrqlimit __ARGS((int argc,char *argv[],void *p));
  66. static int donrreset __ARGS((int argc,char *argv[],void *p));
  67. static int donrretries __ARGS((int argc,char *argv[],void *p));
  68. static int donrroute __ARGS((int argc,char *argv[],void *p));
  69. static int donrstatus __ARGS((int argc,char *argv[],void *p));
  70. static int donrsave __ARGS((int argc,char *argv[],void *p));
  71. static int donrload __ARGS((int argc,char *argv[],void *p));
  72. static int donrttl __ARGS((int argc,char *argv[],void *p));
  73. static int donruser __ARGS((int argc,char *argv[],void *p));
  74. static int donrwindow __ARGS((int argc,char *argv[],void *p));
  75. void doobsotick __ARGS((void));
  76. static int doobsotimer __ARGS((int argc,char *argv[],void *p));
  77. static int dominquality __ARGS((int argc,char *argv[],void *p));
  78. static int donrtype __ARGS((int argc,char *argv[],void *p));
  79. static int donrpromisc __ARGS((int argc,char *argv[],void *p));
  80. static int donrderate __ARGS((int argc,char *argv[],void *p));
  81. static int doroutesort __ARGS((int argc,char *argv[],void *p));
  82. static int donrhidden __ARGS((int argc,char *argv[],void *p));
  83. int donrneighbour __ARGS((int argc,char *argv[],void *p));
  84.  
  85. extern int donr4tdisc __ARGS((int argc,char *argv[],void *p));
  86. extern struct nr_bind *find_best __ARGS((struct nr_bind *list,unsigned obso));
  87. extern void nrresetlinks __ARGS((struct nrroute_tab *rp));
  88.  
  89. static struct cmds DFAR Nrcmds[] = {
  90.     "acktime",    donracktime,    0, 0,    NULLCHAR,
  91.     "alias",    donralias,  0, 0,   NULLCHAR,
  92.     "bcnodes",  dobcnodes,  0, 2,   "netrom bcnodes <iface>",
  93.     "bcpoll",   dobcpoll,   0, 2,   "netrom bcpoll <iface>",
  94. #ifdef ALLSESSIONS
  95.     "connect",  donrconnect, 1024, 2,   "netrom connect <node>",
  96. #endif
  97.     "call",     donrmycall,   0, 0,   NULLCHAR,
  98.     "choketime",    donrchoketime,    0, 0,    NULLCHAR,
  99.     "derate",    donrderate,    0, 0,    NULLCHAR,
  100.     "hidden",   donrhidden, 0, 0,   NULLCHAR,
  101.     "interface",    dointerface,    0, 0, NULLCHAR,
  102.     "irtt",        donrirtt,    0, 0,    NULLCHAR,
  103.     "kick",        donrkick,    0, 2,    "netrom kick <&nrcb>",
  104.     "load",        donrload,    0, 0,    NULLCHAR,
  105.     "minquality",    dominquality,    0, 0,    NULLCHAR,
  106.     "neighbour",    donrneighbour,  0, 0,   NULLCHAR,
  107.     "nodefilter",   donodefilter,   0, 0,   NULLCHAR,
  108.     "nodetimer",    donodetimer,    0, 0,    NULLCHAR,
  109.     "obsotimer",    doobsotimer,    0, 0,    NULLCHAR,
  110.     "promiscuous",    donrpromisc,    0, 0,    NULLCHAR,
  111.     "qlimit",    donrqlimit,    0, 0,    NULLCHAR,
  112.     "route",    donrroute,  0, 0,   NULLCHAR,
  113.     "reset",    donrreset,    0, 2,    "netrom reset <&nrcb>",
  114.     "retries",    donrretries,    0, 0,    NULLCHAR,
  115.     "status",    donrstatus,    0, 0,    NULLCHAR,
  116.     "save",        donrsave,    0, 0,    NULLCHAR,
  117. #ifdef ALLSESSIONS
  118. #ifdef ALLSERV
  119.     "split",    donrconnect, 1024, 2,   "netrom split <node>",
  120. #endif
  121. #endif
  122.     "timertype",    donrtype,   0, 0,   NULLCHAR,
  123.     "ttl",        donrttl,    0, 0,    NULLCHAR,
  124. #ifdef NR4TDISC
  125.     "tdisc",    donr4tdisc, 0, 0,   NULLCHAR,
  126. #endif
  127.     "user",     donruser,   0, 0,   NULLCHAR,
  128.     "window",    donrwindow,    0, 0,    NULLCHAR,
  129.     NULLCHAR,
  130. } ;
  131.  
  132. extern char Myalias[AXALEN];    /* the NETROM alias in 'call' form */
  133. extern char Nralias[ALEN+1];      /* the NETROM alias in 'alias' form */
  134.  
  135. struct timer Nodetimer ; /* timer for nodes broadcasts */
  136. struct timer Obsotimer ; /* timer for aging routes */
  137.  
  138. /* Command multiplexer */
  139. int
  140. donetrom(argc,argv,p)
  141. int argc ;
  142. char *argv[] ;
  143. void *p;
  144. {
  145.     return subcmd(Nrcmds,argc,argv,p) ;
  146. }
  147.  
  148. static struct cmds Routecmds[] = {
  149.     "add",    dorouteadd,    0, 6,
  150.         "netrom route add <alias> <destination> <interface> <quality> <neighbor>",
  151.     "drop",    doroutedrop, 0, 4,
  152.         "netrom route drop <destination> <neighbor> <interface>",
  153.     "info", dorouteinfo, 0, 0,
  154.         "",
  155.     "sort", doroutesort, 0, 1,
  156.         "",
  157.     NULLCHAR,
  158. } ;
  159.  
  160. /* Route command multiplexer */
  161. static int
  162. donrroute(argc, argv,p)
  163. int argc ;
  164. char *argv[] ;
  165. void *p;
  166. {
  167.     if(argc < 2) {
  168.         doroutedump() ;
  169.         return 0 ;
  170.     }
  171.     return subcmd(Routecmds,argc,argv,p) ;
  172. }
  173.  
  174. /* Code to sort Netrom node listing
  175.  * D. Crompton  2/92
  176.  * Dump a list of known netrom routes in
  177.  * sorted order determined by sort
  178.  * flag - default = sort by alias
  179.  */
  180.  
  181. int
  182. doroutedump()
  183. {
  184.     extern unsigned Nr_sorttype;
  185.     register struct nrroute_tab *rp ;
  186.     register int i,j,k, column ;
  187.     char buf[17] ;
  188.     char *cp,*temp ;
  189.     
  190.     column = 1 ;
  191.     
  192.     for(i = 0,j=0 ; i < NRNUMCHAINS ; i++)
  193.         for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ;j++,rp = rp->next);
  194.     if (j) {
  195.         /* Allocate maximum size */
  196.         temp = mallocw (j*17);
  197.     
  198.         for(i = 0,j=0,k=0 ; i < NRNUMCHAINS ; i++)
  199.             for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
  200.                 if(!Nr_hidden && *rp->alias == '#')
  201.                     continue;
  202.                 if (Nr_sorttype) {
  203.                     strcpy(buf,rp->alias) ;
  204.                     /* remove trailing spaces */
  205.                     if((cp = strchr(buf,' ')) == NULLCHAR)
  206.                         cp = &buf[strlen(buf)] ;
  207.                     if(cp != buf)   /* don't include colon for null alias */
  208.                         *cp++ = ':' ;
  209.                     pax25(cp,rp->call) ;
  210.                 } else {
  211.                     pax25(buf,rp->call);
  212.                     cp=&buf[strlen(buf)];
  213.                     *cp++=':';
  214.                     strcpy(cp,rp->alias);
  215.                 }
  216.                 sprintf(&temp[k],"%-16.16s",buf);
  217.                 k+=17;
  218.                 j++;    /* number actually shown */
  219.             }
  220.  
  221.         qsort(temp,(size_t)j,17,strcmp);
  222.         
  223.         for (i=0,k=0;i<j;i++,k+=17) {
  224.             tprintf("%-16s  ",&temp[k]) ;
  225.             if(column++ == 4) {
  226.                 if(tprintf("\n") == EOF) {
  227.                     free(temp);
  228.                     return 0;
  229.                 }
  230.                 column = 1 ;
  231.             }
  232.         }
  233.  
  234.     if(column != 1)
  235.         tputc('\n') ;
  236.     free(temp);
  237.     }
  238.     return 0 ;
  239. }
  240.  
  241. /* netrom Route Dump Sort - ALIAS or CALL first */
  242. static
  243. doroutesort(argc,argv,p)
  244. int argc ;
  245. char *argv[] ;
  246. void *p ;
  247. {
  248.     extern unsigned Nr_sorttype;
  249.  
  250.     if(argc < 2) {
  251.         tprintf("Netrom Sort by %s\n", Nr_sorttype ? "Alias" : "Call" ) ;
  252.         return 0 ;
  253.     }
  254.     
  255.     switch(argv[1][0]) {
  256.         case 'A':
  257.         case 'a':
  258.             Nr_sorttype = 1 ;
  259.             break ;
  260.         case 'C':
  261.         case 'c':
  262.             Nr_sorttype = 0 ;
  263.             break ;
  264.         default:
  265.             tprintf("usage: netrom sort [alias|call]\n") ;
  266.             return -1 ;
  267.     }
  268.  
  269.     return 0 ;
  270. }
  271.  
  272. /* Print detailed information on  ALL routes  (sorted) */
  273. /*  D. Crompton */
  274. void
  275. doallinfo()
  276. {
  277.       extern unsigned Nr_sorttype;
  278.       register struct nrroute_tab *rp ;
  279.       register struct nr_bind *bp ;
  280.       register struct nrnbr_tab *np ;
  281.       char dest[AXALEN] ;
  282.       char neighbor[AXBUF] ;
  283.       char buf[17];
  284.       char *cp,*temp;
  285.       int i,j,k, flow_tmp;
  286.  
  287.       flow_tmp=Current->flowmode;
  288.       Current->flowmode=1;
  289.         
  290.       for (i=0,j=0;i<NRNUMCHAINS;i++)
  291.         for (rp=Nrroute_tab[i];rp!=NULLNRRTAB;rp= rp->next)
  292.            for(bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next,j++); 
  293.            
  294.       if (j) {
  295.  
  296.        temp=mallocw (j*50);
  297.  
  298.        for (i=0,k=0;i<NRNUMCHAINS;i++)
  299.         for (rp=Nrroute_tab[i];rp!=NULLNRRTAB;rp= rp->next)
  300.            for(bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next,k+=50) {
  301.          np = bp->via ;
  302.          if (Nr_sorttype) {
  303.            
  304.            strcpy(buf,rp->alias) ;
  305.            if((cp = strchr(buf,' ')) == NULLCHAR)
  306.                cp = &buf[strlen(buf)] ;
  307.            if(cp != buf) 
  308.                *cp++ = ':' ;
  309.            pax25(cp,rp->call) ;
  310.          
  311.          } else {
  312.            
  313.            pax25(buf,rp->call);
  314.            cp=&buf[strlen(buf)];
  315.            *cp++=':';
  316.            strcpy(cp,rp->alias);
  317.          
  318.          }
  319.  
  320.          sprintf(&temp[k],"%-16s %3d %3d %-8s %-9s %c\n",buf,
  321.              bp->quality,bp->obsocnt,
  322.              np->iface->name,
  323.              pax25(neighbor,np->call),
  324.              (bp->flags & NRB_PERMANENT ? 'P' :
  325.              bp->flags & NRB_RECORDED ? 'R' : 'B'));
  326.             
  327.         }
  328.          qsort(temp,(size_t)j,50,strcmp);
  329.  
  330.          for (i=0,k=0;i<j;i++,k+=50)
  331.         if (tprintf("%s",&temp[k])==EOF)
  332.                break;
  333.          free (temp);
  334.          Current->flowmode=flow_tmp;
  335.        }
  336. }
  337.  
  338.     
  339. /* print detailed information on an individual route
  340.  * Shows alias as well - WG7J
  341.  */
  342. int
  343. dorouteinfo(argc,argv,p)
  344. int argc ;
  345. char *argv[] ;
  346. void *p;
  347. {
  348.     char *cp;
  349.     register struct nrroute_tab *rp ;
  350.     register struct nrroute_tab *npp;
  351.     struct nr_bind *bp ;
  352.     struct nrnbr_tab *np ;
  353.     char dest[AXALEN] ;
  354.     char destbuf[AXBUF];
  355.     char neighbor[AXBUF] ;
  356.     char alias[AXALEN];
  357.     char buf[AXALEN];
  358.     char nb_alias[AXALEN];
  359.     int print_header=1;
  360.     int16 rhash;
  361.  
  362.     if (argc == 1) {
  363.         doallinfo();
  364.         return 0;
  365.     }
  366.  
  367.     putalias(alias,argv[1],0);
  368.     strupr(argv[1]);    /*make sure it's upper case*/
  369.     if((rp = find_nrboth(alias,argv[1])) == NULLNRRTAB){
  370.         /*no such call or node alias*/
  371.         tputs("no such node\n\n");
  372.         return 0;
  373.      }
  374.     /*copy the real alias*/
  375.     strcpy(buf,rp->alias) ;
  376.     if((cp = strchr(buf,' ')) != NULLCHAR)
  377.         *cp = '\0';
  378.  
  379.     for(bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next) {
  380.         np = bp->via ;
  381.         /*now we have to find the alias of the neighbour used
  382.          *so we can print that as well!
  383.          */
  384.         rhash = nrhash(np->call);
  385.         for(npp=Nrroute_tab[rhash];npp!=NULLNRRTAB;npp=npp->next)
  386.             if(addreq(npp->call,np->call))
  387.                 break;
  388.         /* found, now remove trailing spaces */
  389.         strcpy(nb_alias,npp->alias) ;
  390.         if((cp = strchr(nb_alias,' ')) != NULLCHAR)
  391.                 *cp = '\0';
  392.         if(print_header) {
  393.             print_header = 0;
  394.             tputs("      Node          Neighbour       Port  PQual Obsocnt Type\n");
  395.             tprintf("%6s:%-9s  ",buf,pax25(destbuf,rp->call));
  396.         } else
  397.             tputs("                  ");
  398.         tprintf("%6s:%-9s  %-3s    %3d      %d     %c\n",
  399.                  nb_alias,pax25(neighbor,np->call),
  400.                  np->iface->name,
  401.                  bp->quality,bp->obsocnt,
  402.                  bp->flags & NRB_PERMANENT ? 'P' : \
  403.                  (bp->flags & NRB_RECORDED ? 'R' : 'B') );
  404.     }
  405.     tputc('\n');
  406.     return 0 ;
  407. }
  408.  
  409. int
  410. donrneighbour(argc,argv,p)
  411. int argc;
  412. char *argv[];
  413. void *p;
  414. {
  415.     int i,printheader=1;
  416.     struct nrnbr_tab *np;
  417.     struct nrroute_tab *rp;
  418.     struct nr_bind *bind;
  419.     int16 rhash;
  420.     int justused;
  421.     char tmp[AXBUF];
  422.     char alias[AXALEN];
  423.     char *cp;
  424.     int quality = 0;
  425.     int obsocnt = 0;
  426.  
  427.     for(i=0;i<NRNUMCHAINS;i++)  /*loop through all chains of neighbours*/
  428.         for(np=Nrnbr_tab[i];np!=NULLNTAB;np=np->next) {
  429.             if(printheader) {
  430.                 tputs("Routes :\n   Neighbour       Port  PQual Obsocnt Dest\n");
  431.                 printheader = 0;
  432.             }
  433.             /* has this one been used recently ? */
  434.             if((secclock() - np->lastsent) < 60)
  435.                 justused = 1;
  436.             else
  437.                 justused = 0;
  438.  
  439.             /*now we have to find the alias of this neighbour
  440.              *so we can print that as well!
  441.              */
  442.             rhash = nrhash(np->call);
  443.             for(rp=Nrroute_tab[rhash];rp!=NULLNRRTAB;rp=rp->next)
  444.                 if(addreq(rp->call,np->call))
  445.                     break;
  446.  
  447.             if(rp != NULLNRRTAB) {
  448.                 /* found, now remove trailing spaces */
  449.                 strcpy(alias,rp->alias) ;
  450.                 if((cp = strchr(alias,' ')) != NULLCHAR)
  451.                     *cp = '\0';
  452.                 /*find the quality for this neighbour*/
  453.                 bind = find_best(rp->routes,1);
  454.                 quality = bind->quality;
  455.                 obsocnt = bind->obsocnt;
  456.             } else {
  457.                 strcpy(alias,"##TEMP");
  458.             }
  459.  
  460.             /* print it all out */
  461.             tprintf("%s %6s:%-9s  %-5s %4d     %1d    %3d\n",
  462.                     (justused) ? ">" : " ",
  463.                     alias,pax25(tmp,np->call),
  464.                     np->iface->name,
  465.                     quality,obsocnt,np->refcnt);
  466.         }
  467.     if(!printheader)
  468.         tputc('\n');
  469.     return 0;
  470. }
  471.  
  472. #ifdef MAILBOX
  473. extern char Mbnrid[];
  474. extern void setmbnrid();
  475. #endif
  476.  
  477. /* define the netrom alias*/
  478. static int
  479. donralias(argc,argv,p)
  480. int argc ;
  481. char *argv[] ;
  482. void *p;
  483. {
  484.     int len;
  485.     char tmp[AXBUF];
  486.  
  487.     if(argc < 2) {
  488.         tprintf("%s\n",pax25(tmp,Myalias));
  489.         return 0;
  490.     }
  491.     if((setcall(Myalias,argv[1]) == -1) ||
  492.        (putalias(Nralias,argv[1],1) == -1)) {
  493.             tputs("can't set alias\n");
  494.             return 0;
  495.     }
  496. #ifdef MAILBOX
  497.     setmbnrid();
  498. #endif
  499.     return 0;
  500. }
  501.  
  502. /* define the netrom call,
  503.  * this simply changes the interface linkaddress!
  504.  * but is a little easier to use...
  505.  */
  506. static int
  507. donrmycall(argc,argv,p)
  508. int argc ;
  509. char *argv[] ;
  510. void *p;
  511. {
  512.     int len;
  513.     char tmp[AXALEN];
  514.  
  515.     if(Nr_iface == NULLIF) {
  516.         tputs("Attach netrom interface first\n") ;
  517.         return 1 ;
  518.     }
  519.  
  520.     if(argc < 2) {
  521.         if (Nr_iface->hwaddr == NULLCHAR)
  522.             tputs("not set\n");
  523.         else
  524.             tprintf("%s\n",pax25(tmp,Nr_iface->hwaddr));
  525.     } else {
  526.         if( (len=strlen(argv[1])) > (AXBUF - 1)) {
  527.             tputs("too long\n");
  528.             return 1;
  529.         }
  530.         if(Nr_iface->hwaddr != NULLCHAR)
  531.             free(Nr_iface->hwaddr);
  532.         Nr_iface->hwaddr = mallocw(Nr_iface->iftype->hwalen);
  533.         (*Nr_iface->iftype->scan)(Nr_iface->hwaddr,argv[1]);
  534. #ifdef MAILBOX
  535.         setmbnrid();
  536. #endif
  537.     }
  538.     return 0;
  539. }
  540.  
  541. /* make an interface available to net/rom */
  542. /* arguments are:
  543.  * argv[0] - "interface"
  544.  * argv[1] - "iface" , the interface name
  545.  * argv[2] - "quality", the interface broadcast quality
  546.  * argv[3] - "n" or "v", to override the default (verbose)
  547.  *            n = never broadcast verbose
  548.  *            v = always broadcast verbose
  549.  */
  550. static
  551. int
  552. dointerface(argc,argv,p)
  553. int argc ;
  554. char *argv[] ;
  555. void *p;
  556. {
  557.     register struct iface *ifp ;
  558.     int i,mtu ;
  559.  
  560.     if(Nr_iface == NULLIF) {
  561.         tputs("Attach netrom interface first\n") ;
  562.         return 1 ;
  563.     }
  564.  
  565.     if(argc < 3) {
  566.         i = 0;
  567.         for(ifp=Ifaces;ifp;ifp=ifp->next) {
  568.             if(ifp->flags & IS_NR_IFACE){
  569.                 if(!i) {
  570.                     i = 1;
  571.                     tputs("Iface  Qual Verbose\n");
  572.                 }
  573.                 tprintf("%-6s %-3d     %c\n",
  574.                         ifp->name,ifp->quality,
  575.                         (ifp->flags & NR_VERBOSE)?'Y':'N');
  576.             }
  577.         }
  578.         return 0;
  579.     }
  580.  
  581.     if((ifp = if_lookup(argv[1])) == NULLIF){
  582.         tprintf(Badinterface,argv[1]);
  583.         return 1;
  584.     }
  585.  
  586.     if(ifp->type != CL_AX25){
  587.         tprintf("Interface %s is not NETROM compatible\n",argv[1]);
  588.         return 1;
  589.     }
  590.  
  591.     /* activate the interface */
  592.     ifp->flags |= IS_NR_IFACE;
  593.  
  594.     /* set quality */
  595.     if((ifp->quality=atoi(argv[2])) > 255) /*Maximum quality possible*/
  596.         ifp->quality = 255;
  597.     /*check to see if quality is not 0 */
  598.     if(ifp->quality == 0)
  599.         ifp->quality = 1;
  600.  
  601.     /* default is none-verbose */
  602.     ifp->flags &= ~NR_VERBOSE;
  603.     if(argc > 3)
  604.         if(*argv[3] == 'v')
  605.             ifp->flags |= NR_VERBOSE;
  606.  
  607.     /* Check, and set the NETROM MTU - WG7J */
  608.     if((mtu = ifp->paclen - 20) < Nr_iface->mtu)
  609.             Nr_iface->mtu = mtu;
  610.  
  611.     /* Poll other nodes on this interface */
  612.     nr_bcpoll(ifp);
  613.  
  614.     return 0 ;
  615. }
  616.  
  617.         
  618. /* convert a null-terminated alias name to a blank-filled, upcased */
  619. /* version.  Return -1 on failure. */
  620. int
  621. putalias(to,from,complain)
  622. register char *to, *from ;
  623. int complain ;    
  624. {
  625.     int len, i ;
  626.     
  627.     if((len = strlen(from)) > ALEN) {
  628.         if(complain)
  629.             tprintf("alias too long - six characters max\n") ;
  630.         return -1 ;
  631.     }
  632.     
  633.     for(i = 0 ; i < ALEN ; i++) {
  634.         if(i < len) {
  635.             if(islower(*from))
  636.                 *to++ = toupper(*from++) ;
  637.             else
  638.                 *to++ = *from++ ;
  639.         }
  640.         else
  641.             *to++ = ' ' ;
  642.     }
  643.             
  644.     *to = '\0' ;
  645.     return 0 ;
  646. }
  647.  
  648. /* Add a route */
  649. static int
  650. dorouteadd(argc, argv,p)
  651. int argc ;
  652. char *argv[] ;
  653. void *p;
  654. {
  655.     char alias[AXALEN] ;
  656.     char dest[AXALEN] ;
  657.     unsigned quality ;
  658.     char neighbor[AXALEN] ;
  659.     struct iface *ifp;
  660.     int naddr ;
  661.  
  662.     /* format alias (putalias prints error message if necessary) */
  663.     if(putalias(alias,argv[1],1) == -1)
  664.         return -1 ;
  665.  
  666.     /* format destination callsign */
  667.     if(setcall(dest,argv[2]) == -1) {
  668.         tprintf("bad destination callsign\n") ;
  669.         return -1 ;
  670.     }
  671.  
  672.     /* find interface */
  673.     if((ifp = if_lookup(argv[3])) == NULLIF) {
  674.         tprintf(Badinterface,argv[3]);
  675.         return 1;
  676.     }
  677.  
  678.     /* Is it a netrom interface ? */
  679.     if(!(ifp->flags & IS_NR_IFACE)) {
  680.         tprintf(Badinterface,argv[3]) ;
  681.         return -1 ;
  682.     }
  683.     
  684.     /* get and check quality value */
  685.     if((quality = atoi(argv[4])) > 255) {
  686.         tprintf("maximum route quality is 255\n") ;
  687.         return -1 ;
  688.     }
  689.  
  690.     /* Change from 871225 -- no digis in net/rom table */
  691.     naddr = argc - 5 ;
  692.     if(naddr > 1) {
  693.         tprintf("Use the ax25 route command to specify digipeaters\n") ;
  694.         return -1 ;
  695.     }
  696.     
  697.     /* format neighbor address string */
  698.     setcall(neighbor,argv[5]) ;
  699.  
  700.     return nr_routeadd(alias,dest,ifp,quality,neighbor,1,0) ;
  701. }
  702.  
  703.  
  704. /* drop a route */
  705. static int
  706. doroutedrop(argc,argv,p)
  707. int argc ;
  708. char *argv[] ;
  709. void *p;
  710. {
  711.     char dest[AXALEN], neighbor[AXALEN] ;
  712.     struct iface *ifp;
  713.  
  714.     /* format destination and neighbor callsigns */
  715.     if(setcall(dest,argv[1]) == -1) {
  716.         tprintf("bad destination callsign\n") ;
  717.         return -1 ;
  718.     }
  719.     if(setcall(neighbor,argv[2]) == -1) {
  720.         tprintf("bad neighbor callsign\n") ;
  721.         return -1 ;
  722.     }
  723.  
  724.     /* find interface */
  725.     if((ifp = if_lookup(argv[3])) == NULLIF) {
  726.         tprintf(Badinterface,argv[3]);
  727.         return 1;
  728.     }
  729.  
  730.     /* Is it a netrom interface ? */
  731.     if(!(ifp->flags & IS_NR_IFACE)) {
  732.         tprintf(Badinterface,argv[3]) ;
  733.         return -1 ;
  734.     }
  735.     
  736.     return nr_routedrop(dest,neighbor,ifp) ;
  737. }
  738.  
  739. /* Broadcast nodes list on named interface. */
  740. static int
  741. dobcnodes(argc,argv,p)
  742. int argc ;
  743. char *argv[] ;
  744. void *p;
  745. {
  746.     struct iface *ifp;
  747.  
  748.     /* find interface */
  749.     if((ifp = if_lookup(argv[1])) == NULLIF) {
  750.         tprintf(Badinterface,argv[1]);
  751.         return 1;
  752.     }
  753.  
  754.     /* Is it a netrom interface ? */
  755.     if(!(ifp->flags & IS_NR_IFACE)) {
  756.         tprintf(Badinterface,argv[1]) ;
  757.         return -1 ;
  758.     }
  759.     nr_bcnodes(ifp) ;
  760.     return 0;
  761. }
  762.  
  763. /* Poll nodes for routes on named interface. - WG7J */
  764. static int
  765. dobcpoll(argc,argv,p)
  766. int argc ;
  767. char *argv[] ;
  768. void *p;
  769. {
  770.     struct iface *ifp;
  771.  
  772.     /* find interface */
  773.     if((ifp = if_lookup(argv[1])) == NULLIF) {
  774.         tprintf(Badinterface,argv[1]);
  775.         return 1;
  776.     }
  777.  
  778.     /* Is it a netrom interface ? */
  779.     if(!(ifp->flags & IS_NR_IFACE)) {
  780.         tprintf(Badinterface,argv[1]) ;
  781.         return -1 ;
  782.     }
  783.  
  784.     nr_bcpoll(ifp) ;
  785.     return 0;
  786. }
  787.  
  788. /* Set outbound node broadcast interval */
  789. static int
  790. donodetimer(argc,argv,p)
  791. int argc;
  792. char *argv[];
  793. void *p;
  794. {
  795.     if(argc < 2){
  796.         tprintf("Nodetimer %lu/%lu seconds\n",
  797.             read_timer(&Nodetimer)/1000L,
  798.             dur_timer(&Nodetimer)/1000L);
  799.         return 0;
  800.     }
  801.     stop_timer(&Nodetimer) ;    /* in case it's already running */
  802.     Nodetimer.func = (void (*)())donodetick;/* what to call on timeout */
  803.     Nodetimer.arg = NULLCHAR;        /* dummy value */
  804.     set_timer(&Nodetimer,atoi(argv[1])*1000L);    /* set timer duration */
  805.     start_timer(&Nodetimer);        /* and fire it up */
  806.     return 0;
  807. }
  808.  
  809. void
  810. donodetick()
  811. {
  812.     struct iface *ifp;
  813.  
  814.     for(ifp=Ifaces;ifp;ifp=ifp->next)
  815.         if(ifp->flags & IS_NR_IFACE)
  816.             nr_bcnodes(ifp) ;
  817.  
  818.     /* Restart timer */
  819.     start_timer(&Nodetimer) ;
  820. }
  821.  
  822. /* Set timer for aging routes */
  823. static int
  824. doobsotimer(argc,argv,p)
  825. int argc;
  826. char *argv[];
  827. void *p;
  828. {
  829.     if(argc < 2){
  830.         tprintf("Obsotimer %lu/%lu seconds\n",
  831.             read_timer(&Obsotimer)/1000L,
  832.             dur_timer(&Obsotimer)/1000L);
  833.         return 0;
  834.     }
  835.     stop_timer(&Obsotimer) ;    /* just in case it's already running */
  836.     Obsotimer.func = (void (*)())doobsotick;/* what to call on timeout */
  837.     Obsotimer.arg = NULLCHAR;        /* dummy value */
  838.     set_timer(&Obsotimer,atoi(argv[1])*1000L);    /* set timer duration */
  839.     start_timer(&Obsotimer);        /* and fire it up */
  840.     return 0;
  841. }
  842.  
  843.  
  844. /* Go through the routing table, reducing the obsolescence count of
  845.  * non-permanent routes, and purging them if the count reaches 0
  846.  */
  847. void
  848. doobsotick()
  849. {
  850.     register struct nrnbr_tab *np ;
  851.     register struct nrroute_tab *rp, *rpnext ;
  852.     register struct nr_bind *bp, *bpnext ;
  853.     int i ;
  854.  
  855.     for(i = 0 ; i < NRNUMCHAINS ; i++) {
  856.         for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rpnext) {
  857.             rpnext = rp->next ;     /* save in case we free this route */
  858.             /* Check all bindings for this route */
  859.             for(bp = rp->routes ; bp != NULLNRBIND ; bp = bpnext) {
  860.                 bpnext = bp->next ;    /* in case we free this binding */
  861.                 if(bp->flags & NRB_PERMANENT)    /* don't age these */
  862.                     continue ;
  863.                 if(--bp->obsocnt == 0) {        /* time's up! */
  864.                     if(bp->next != NULLNRBIND)
  865.                         bp->next->prev = bp->prev ;
  866.                     if(bp->prev != NULLNRBIND)
  867.                         bp->prev->next = bp->next ;
  868.                     else
  869.                         rp->routes = bp->next ;
  870.                     rp->num_routes-- ;            /* one less binding */
  871.                     np = bp->via ;                /* find the neighbor */
  872.                     free((char *)bp) ;                /* now we can free the bind */
  873.                     /* Check to see if we can free the neighbor */
  874.                     if(--np->refcnt == 0) {
  875.                         if(np->next != NULLNTAB)
  876.                             np->next->prev = np->prev ;
  877.                         if(np->prev != NULLNTAB)
  878.                             np->prev->next = np->next ;
  879.                         else {
  880.                             Nrnbr_tab[nrhash(np->call)] = np->next ;
  881.                         }
  882.                         free((char *)np) ;    /* free the storage */
  883.                     }
  884.                 }
  885.             }
  886.             if(rp->num_routes == 0) {        /* did we free them all? */
  887.                 if(rp->next != NULLNRRTAB)
  888.                     rp->next->prev = rp->prev ;
  889.                 if(rp->prev != NULLNRRTAB)
  890.                     rp->prev->next = rp->next ;
  891.                 else
  892.                     Nrroute_tab[i] = rp->next ;
  893.                 /* No more routes left !
  894.                  * We should close/reset any netrom connections
  895.                  * still idling for this route ! - WG7J
  896.                  */
  897.                 nrresetlinks(rp);
  898.                 free((char *)rp) ;
  899.             }
  900.         }
  901.     }
  902.  
  903.     start_timer(&Obsotimer) ;
  904. }
  905.  
  906.  
  907. static struct cmds Nfcmds[] = {
  908.     "add",    donfadd,    0, 3,
  909.         "netrom nodefilter add <neighbor> <interface> [quality]",
  910.     "drop",    donfdrop,    0, 3,
  911.         "netrom nodefilter drop <neighbor> <interface>",
  912.     "mode",    donfmode,    0, 0,    NULLCHAR,
  913.     NULLCHAR,    NULLFP,    0, 0,
  914.         "nodefilter subcommands: add drop mode",
  915. } ;
  916.  
  917. /* nodefilter command multiplexer */
  918. static int
  919. donodefilter(argc,argv,p)
  920. int argc ;
  921. char *argv[] ;
  922. void *p;
  923. {
  924.     if(argc < 2) {
  925.         donfdump() ;
  926.         return 0 ;
  927.     }
  928.     return subcmd(Nfcmds,argc,argv,p) ;
  929. }
  930.  
  931. /* display a list of <callsign,interface> pairs from the filter
  932.  * list.
  933.  */
  934. static int
  935. donfdump()
  936. {
  937.     int i, column = 1 ;
  938.     struct nrnf_tab *fp ;
  939.     char buf[AXBUF] ;
  940.  
  941.     for(i = 0 ; i < NRNUMCHAINS ; i++)
  942.         for(fp = Nrnf_tab[i] ; fp != NULLNRNFTAB ; fp = fp->next) {
  943.             pax25(buf,fp->neighbor) ;
  944.             tprintf("%-7s  %-8s  %-3d   ",
  945.              buf,fp->iface->name, fp->quality) ;
  946.             if(column++ == 3) {
  947.                 if(tprintf("\n") == EOF)
  948.                     return 0;
  949.                 column = 1 ;
  950.             }
  951.         }
  952.  
  953.     if(column != 1)
  954.         tprintf("\n") ;
  955.  
  956.     return 0 ;
  957. }
  958.  
  959. /* add an entry to the filter table */
  960. static int
  961. donfadd(argc,argv,p)
  962. int argc ;
  963. char *argv[] ;
  964. void *p;
  965. {
  966.     struct iface *ifp;
  967.     unsigned qual;
  968.     char neighbor[AXALEN] ;
  969.  
  970.     /* format callsign */
  971.     if(setcall(neighbor,argv[1]) == -1) {
  972.         tprintf("bad neighbor callsign\n") ;
  973.         return -1 ;
  974.     }
  975.  
  976.     /* find interface */
  977.     if((ifp = if_lookup(argv[2])) == NULLIF) {
  978.         tprintf(Badinterface,argv[2]);
  979.         return 1;
  980.     }
  981.  
  982.     /* Is it a netrom interface ? */
  983.     if(!(ifp->flags & IS_NR_IFACE)) {
  984.         tprintf(Badinterface,argv[2]) ;
  985.         return -1 ;
  986.     }
  987.  
  988.     qual = ifp->quality; /* set default quality */
  989.  
  990.     if(argc > 3)
  991.         qual = atoi(argv[3]);
  992.  
  993.     return nr_nfadd(neighbor,ifp,qual) ;
  994. }
  995.  
  996. /* drop an entry from the filter table */
  997. static int
  998. donfdrop(argc,argv,p)
  999. int argc ;
  1000. char *argv[] ;
  1001. void *p;
  1002. {
  1003.     struct iface *ifp;
  1004.     char neighbor[AXALEN] ;
  1005.  
  1006.     /* format neighbor callsign */
  1007.     if(setcall(neighbor,argv[1]) == -1) {
  1008.         tprintf("bad neighbor callsign\n") ;
  1009.         return -1 ;
  1010.     }
  1011.  
  1012.     /* find interface */
  1013.     if((ifp = if_lookup(argv[2])) == NULLIF) {
  1014.         tprintf(Badinterface,argv[2]);
  1015.         return 1;
  1016.     }
  1017.  
  1018.     /* Is it a netrom interface ? */
  1019.     if(!(ifp->flags & IS_NR_IFACE)) {
  1020.         tprintf(Badinterface,argv[2]) ;
  1021.         return -1 ;
  1022.     }
  1023.  
  1024.     return nr_nfdrop(neighbor,ifp) ;
  1025. }
  1026.  
  1027. /* nodefilter mode subcommand */
  1028. static int
  1029. donfmode(argc,argv,p)
  1030. int argc ;
  1031. char *argv[] ;
  1032. void *p;
  1033. {
  1034.     if(argc < 2) {
  1035.         tprintf("filter mode is ") ;
  1036.         switch(Nr_nfmode) {
  1037.             case NRNF_NOFILTER:
  1038.                 tprintf("none\n") ;
  1039.                 break ;
  1040.             case NRNF_ACCEPT:
  1041.                 tprintf("accept\n") ;
  1042.                 break ;
  1043.             case NRNF_REJECT:
  1044.                 tprintf("reject\n") ;
  1045.                 break ;
  1046.             default:
  1047.                 tprintf("some strange, unknown value\n") ;
  1048.         }
  1049.         return 0 ;
  1050.     }
  1051.     
  1052.     switch(argv[1][0]) {
  1053.         case 'n':
  1054.         case 'N':
  1055.             Nr_nfmode = NRNF_NOFILTER ;
  1056.             break ;
  1057.         case 'a':
  1058.         case 'A':
  1059.             Nr_nfmode = NRNF_ACCEPT ;
  1060.             break ;
  1061.         case 'r':
  1062.         case 'R':
  1063.             Nr_nfmode = NRNF_REJECT ;
  1064.             break ;
  1065.         default:
  1066.             tprintf("modes are: none accept reject\n") ;
  1067.             return -1 ;
  1068.     }
  1069.  
  1070.     return 0 ;
  1071. }
  1072.  
  1073. /* netrom network packet time-to-live initializer */
  1074. static int
  1075. donrttl(argc, argv,p)
  1076. int argc ;
  1077. char *argv[] ;
  1078. void *p;
  1079. {
  1080.     return setshort(&Nr_ttl,"Time to live",argc,argv);
  1081. }
  1082.  
  1083. /* show hidden (ie '#...') nodes or not */
  1084. static int
  1085. donrhidden(argc,argv,p)
  1086. int argc ;
  1087. char *argv[] ;
  1088. void *p;
  1089. {
  1090.     return setbool(&Nr_hidden,"Hidden nodes",argc,argv);
  1091. }
  1092.  
  1093. /* allow automatic derating of netrom routes on link failure */
  1094. static int
  1095. donrderate(argc,argv,p)
  1096. int argc ;
  1097. char *argv[] ;
  1098. void *p;
  1099. {
  1100.     extern int Nr_derate;
  1101.  
  1102.     return setbool(&Nr_derate,"Derate flag",argc,argv);
  1103. }
  1104.  
  1105. /* promiscuous acceptance of broadcasts */
  1106. static int
  1107. donrpromisc(argc,argv,p)
  1108. int argc ;
  1109. char *argv[] ;
  1110. void *p;
  1111. {
  1112.     extern int Nr_promisc;
  1113.  
  1114.     return setbool(&Nr_promisc,"Promiscuous flag",argc,argv);
  1115. }
  1116.  
  1117. #ifdef ALLSESSIONS
  1118. /* Initiate a NET/ROM transport connection */
  1119. static int
  1120. donrconnect(argc,argv,p)
  1121. int argc ;
  1122. char *argv[] ;
  1123. void *p;
  1124. {
  1125.     struct nrroute_tab *np;
  1126.     struct sockaddr_nr lsocket, fsocket;
  1127.     char alias[AXBUF];
  1128.     struct session *sp;
  1129.     int split = 0;
  1130.  
  1131.     /*Make sure this comes from console - WG7J*/
  1132.     if(Curproc->input != Command->input)
  1133.         return 0;
  1134.  
  1135. #ifdef ALLSERV
  1136.     if(argv[0][0] == 's')
  1137.         split  = 1;
  1138. #endif
  1139.  
  1140.     /* Get a session descriptor */
  1141.     if((sp = newsession(argv[1],NRSESSION,split)) == NULLSESSION) {
  1142.         tputs(TooManySessions);
  1143.         return 1 ;
  1144.     }
  1145.  
  1146.     if((sp->s = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1){
  1147.         tputs(Nosock);
  1148.         keywait(NULLCHAR,1);
  1149.         freesession(sp);
  1150.         return 1;
  1151.     }
  1152.  
  1153.     /* See if the requested destination is a known alias or call,
  1154.      * use it if it is.  Otherwize give an error message. - WG7J
  1155.      */
  1156.     putalias(alias,argv[1],0);
  1157.     strupr(argv[1]);    /*make sure it's upper case*/
  1158.     if((np = find_nrboth(alias,argv[1])) == NULLNRRTAB){
  1159.         /*no such call or node alias*/
  1160.         tputs("no such node\n\n");
  1161.         keywait(NULLCHAR,1);
  1162.         freesession(sp);
  1163.         return 1;
  1164.     }
  1165.  
  1166.     /* Setup the local side of the connection */
  1167.     lsocket.nr_family = AF_NETROM;
  1168.  
  1169.     /* Set up our local username, bind would use Mycall instead */
  1170.     memcpy(lsocket.nr_addr.user,Nr4user,AXALEN);
  1171.  
  1172.     /* Putting anything else than Nr_iface->hwaddr here will not work ! */
  1173.     memcpy(lsocket.nr_addr.node,Nr_iface->hwaddr,AXALEN);
  1174.  
  1175.     /* Now bind the socket to this */
  1176.     bind(sp->s,(char *)&lsocket,sizeof(struct sockaddr_nr));
  1177.  
  1178.     
  1179.     /* Set up the remote side of the connection */
  1180.     fsocket.nr_family = AF_NETROM;
  1181.     memcpy(fsocket.nr_addr.user,np->call,AXALEN);
  1182.     memcpy(fsocket.nr_addr.node,np->call,AXALEN);
  1183.     fsocket.nr_family = AF_NETROM;
  1184.  
  1185.     return tel_connect(sp, (char *)&fsocket, sizeof(struct sockaddr_nr));
  1186. }
  1187. #endif
  1188.  
  1189. /* Reset a net/rom connection abruptly */
  1190. static int
  1191. donrreset(argc,argv,p)
  1192. int argc;
  1193. char *argv[];
  1194. void *p;
  1195. {
  1196.     struct nr4cb *cb ;
  1197.  
  1198. #ifndef TNOS_68K
  1199.     cb = MK_FP(htoi(argv[1]),8);
  1200. #else
  1201.     cb = htoi(argv[1]);
  1202. #endif
  1203.     if(!nr4valcb(cb)){
  1204.         tprintf(Notval);
  1205.         return 1;
  1206.     }
  1207.     reset_nr4(cb);
  1208.     return 0;
  1209. }
  1210.  
  1211. /* Force retransmission on a net/rom connection */
  1212.  
  1213. static int
  1214. donrkick(argc,argv,p)
  1215. int argc;
  1216. char *argv[];
  1217. void *p;
  1218. {
  1219.     struct nr4cb *cb ;
  1220.  
  1221. #ifndef TNOS_68K
  1222.     cb = MK_FP(htoi(argv[1]),8);
  1223. #else
  1224.     cb = htoi(argv[1]);
  1225. #endif
  1226.     if(kick_nr4(cb) == -1) {
  1227.         tprintf(Notval);
  1228.         return 1;
  1229.     } else
  1230.         return 0;
  1231. }
  1232.  
  1233. /* netrom transport ACK delay timer */
  1234. static int
  1235. donracktime(argc, argv,p)
  1236. int argc ;
  1237. char *argv[] ;
  1238. void *p;
  1239. {
  1240.     return setlong(&Nr4acktime,"Ack delay time (ms)",argc,argv);
  1241. }
  1242.  
  1243. /* netrom transport choke timeout */
  1244. static int
  1245. donrchoketime(argc, argv,p)
  1246. int argc ;
  1247. char *argv[] ;
  1248. void *p;
  1249. {
  1250.     return setlong(&Nr4choketime,"Choke timeout (ms)",argc,argv);
  1251. }
  1252.  
  1253. /* netrom transport initial round trip time */
  1254.  
  1255. static int
  1256. donrirtt(argc, argv,p)
  1257. int argc ;
  1258. char *argv[] ;
  1259. void *p;
  1260. {
  1261.     return setlong(&Nr4irtt,"Initial RTT (ms)",argc,argv);
  1262. }
  1263.  
  1264. /* netrom transport receive queue length limit.  This is the */
  1265. /* threshhold at which we will CHOKE the sender. */
  1266.  
  1267. static int
  1268. donrqlimit(argc, argv,p)
  1269. int argc ;
  1270. char *argv[] ;
  1271. void *p;
  1272. {
  1273.     return setshort(&Nr4qlimit,"Queue limit (bytes)",argc,argv);
  1274. }
  1275.  
  1276. /* Display or change our NET/ROM username */
  1277. static int
  1278. donruser(argc,argv,p)
  1279. int argc;
  1280. char *argv[];
  1281. void *p;
  1282. {
  1283.     char buf[AXBUF];
  1284.  
  1285.     if(argc < 2){
  1286.         pax25(buf,Nr4user);
  1287.         tprintf("%s\n",buf);
  1288.         return 0;
  1289.     }
  1290.     if(setcall(Nr4user,argv[1]) == -1)
  1291.         return -1;
  1292.     Nr4user[ALEN] |= E;
  1293.     return 0;
  1294. }
  1295.  
  1296. /* netrom transport maximum window.  This is the largest send and */
  1297. /* receive window we may negotiate */
  1298.  
  1299. static int
  1300. donrwindow(argc, argv,p)
  1301. int argc ;
  1302. char *argv[] ;
  1303. void *p;
  1304. {
  1305.     return setshort(&Nr4window,"Window (frames)",argc,argv);
  1306. }
  1307.  
  1308. /* netrom transport maximum retries.  This is used in connect and */
  1309. /* disconnect attempts; I haven't decided what to do about actual */
  1310. /* data retries yet. */
  1311.  
  1312. static int
  1313. donrretries(argc, argv,p)
  1314. int argc ;
  1315. char *argv[] ;
  1316. void *p;
  1317. {
  1318.     return setshort(&Nr4retries,"Retry limit",argc,argv);
  1319. }
  1320.  
  1321.  
  1322. /* Display the status of NET/ROM connections */
  1323.  
  1324. static int
  1325. donrstatus(argc, argv,p)
  1326. int argc ;
  1327. char *argv[] ;
  1328. void *p;
  1329. {
  1330.     int i ;
  1331.     struct nr4cb *cb ;
  1332.     char luser[AXBUF], ruser[AXBUF], node[AXBUF] ;
  1333.     
  1334.     if(argc < 2) {
  1335.         tprintf("&NCB Snd-W Snd-Q Rcv-Q     LUser      RUser @Node     State\n");
  1336.         for(i = 0 ; i < NR4MAXCIRC ; i++) {
  1337.             if((cb = Nr4circuits[i].ccb) == NULLNR4CB)
  1338.                 continue ;
  1339.             pax25(luser,cb->local.user) ;
  1340.             pax25(ruser,cb->remote.user) ;
  1341.             pax25(node,cb->remote.node) ;
  1342.             if(tprintf("%4.4x   %3d %5d %5d %9s  %9s %-9s %s\n",
  1343.              FP_SEG(cb), cb->nbuffered, len_q(cb->txq),
  1344.              len_p(cb->rxq), luser, ruser, node,
  1345.              Nr4states[cb->state]) == EOF)
  1346.                 break;
  1347.         }
  1348.         return 0 ;
  1349.     }
  1350. #ifndef TNOS_68K
  1351.     cb = MK_FP(htoi(argv[1]),8);
  1352. #else
  1353.     cb = htoi(argv[1]);
  1354. #endif
  1355.     if(!nr4valcb(cb)) {
  1356.         tprintf(Notval) ;
  1357.         return 1 ;
  1358.     }
  1359.     donrdump(cb) ;
  1360.     return 0 ;
  1361. }
  1362.  
  1363. /* Dump one control block */
  1364.  
  1365. void
  1366. donrdump(cb)
  1367. struct nr4cb *cb ;
  1368. {
  1369.     char luser[AXBUF], ruser[AXBUF], node[AXBUF] ;
  1370.     unsigned seq ;
  1371.     struct nr4txbuf *b ;
  1372.     struct timer *t ;
  1373.  
  1374.     pax25(luser,cb->local.user) ;
  1375.     pax25(ruser,cb->remote.user) ;
  1376.     pax25(node,cb->remote.node) ;
  1377.  
  1378.     tprintf("Local: %s %d/%d Remote: %s @ %s %d/%d State: %s\n",
  1379.            luser, cb->mynum, cb->myid, ruser, node,
  1380.            cb->yournum, cb->yourid, Nr4states[cb->state]) ;
  1381.  
  1382.     tprintf("Window: %-5u Rxpect: %-5u RxNext: %-5u RxQ: %-5d %s\n",
  1383.            cb->window, uchar(cb->rxpected), uchar(cb->rxpastwin),
  1384.            len_p(cb->rxq), cb->qfull ? "RxCHOKED" : "") ;
  1385.  
  1386.     tprintf(" Unack: %-5u Txpect: %-5u TxNext: %-5u TxQ: %-5d %s\n",
  1387.            cb->nbuffered, uchar(cb->ackxpected), uchar(cb->nextosend),
  1388.            len_q(cb->txq), cb->choked ? "TxCHOKED" : "") ;
  1389.  
  1390.     tprintf("TACK: ") ;
  1391.     if(run_timer(&cb->tack))
  1392.         tprintf("%lu", read_timer(&cb->tack)) ;
  1393.     else
  1394.         tprintf("stop") ;
  1395.     tprintf("/%lu ms; ", dur_timer(&cb->tack)) ;
  1396.  
  1397.     tprintf("TChoke: ") ;
  1398.     if(run_timer(&cb->tchoke))
  1399.         tprintf("%lu", read_timer(&cb->tchoke)) ;
  1400.     else
  1401.         tprintf("stop") ;
  1402.     tprintf("/%lu ms; ", dur_timer(&cb->tchoke)) ;
  1403.  
  1404.     tprintf("TCD: ") ;
  1405.     if(run_timer(&cb->tcd))
  1406.         tprintf("%lu", read_timer(&cb->tcd)) ;
  1407.     else
  1408. #ifndef NR4TDISC
  1409.         tprintf("stop") ;
  1410.     tprintf("/%lu ms", dur_timer(&cb->tcd)) ;
  1411. #else
  1412.         tprintf("stop") ;
  1413.     tprintf("/%lu ms; ", dur_timer(&cb->tcd)) ;
  1414.  
  1415.     tprintf("TDisc: ") ;
  1416.     if(run_timer(&cb->tdisc))
  1417.         tprintf("%lu", (read_timer(&cb->tdisc)/1000L)) ;
  1418.     else
  1419.         tprintf("stop") ;
  1420.     tprintf("/%lu", (dur_timer(&cb->tdisc)/1000L)) ;
  1421. #endif
  1422.  
  1423.     if(run_timer(&cb->tcd))
  1424.         tprintf("; Tries: %u\n", cb->cdtries) ;
  1425.     else
  1426.         tputc('\n') ;
  1427.  
  1428.     tprintf("Backoff Level %u SRTT %ld ms Mean dev %ld ms\n",
  1429.            cb->blevel, cb->srtt, cb->mdev) ;
  1430.  
  1431.     /* If we are connected and the send window is open, display */
  1432.     /* the status of all the buffers and their timers */
  1433.     
  1434.     if(cb->state == NR4STCON && cb->nextosend != cb->ackxpected) {
  1435.  
  1436.         tprintf("TxBuffers:  Seq  Size  Tries  Timer\n") ;
  1437.  
  1438.         for(seq = cb->ackxpected ;
  1439.              nr4between(cb->ackxpected, seq, cb->nextosend) ;
  1440.              seq = (seq + 1) & NR4SEQMASK) {
  1441.  
  1442.             b = &cb->txbufs[seq % cb->window] ;
  1443.             t = &b->tretry ;
  1444.  
  1445.             if(tprintf("            %3u   %3d  %5d  %lu/%lu\n",
  1446.              seq, len_p(b->data), b->retries + 1,
  1447.              read_timer(t), dur_timer(t))
  1448.              == EOF)
  1449.                 break;
  1450.         }
  1451.  
  1452.     }
  1453.  
  1454. }
  1455.  
  1456. /* netrom timers type - linear v exponential */
  1457. static
  1458. donrtype(argc,argv,p)
  1459. int argc ;
  1460. char *argv[] ;
  1461. void *p ;
  1462. {
  1463.     extern unsigned Nr_timertype;
  1464.  
  1465.     if(argc < 2) {
  1466.         tprintf("Netrom timer type is %s\n", Nr_timertype ? "linear" : "exponential" ) ;
  1467.         return 0 ;
  1468.     }
  1469.     
  1470.     switch(argv[1][0]) {
  1471.         case 'l':
  1472.         case 'L':
  1473.             Nr_timertype = 1 ;
  1474.             break ;
  1475.         case 'e':
  1476.         case 'E':
  1477.             Nr_timertype = 0 ;
  1478.             break ;
  1479.         default:
  1480.             tprintf("use: netrom timertype [linear|exponential]\n") ;
  1481.             return -1 ;
  1482.     }
  1483.  
  1484.     return 0 ;
  1485. }
  1486.  
  1487. static
  1488. dominquality(argc,argv,p)
  1489. int argc ;
  1490. char *argv[] ;
  1491. void *p ;
  1492. {
  1493.     unsigned val ;
  1494.     extern unsigned Nr_autofloor;
  1495.  
  1496.     if(argc < 2) {
  1497.         tprintf("%u\n", Nr_autofloor) ;
  1498.         return 0 ;
  1499.     }
  1500.  
  1501.     val = atoi(argv[1]) ;
  1502.  
  1503.     if(val == 0 || val > 255 ) {
  1504.         tprintf("The minimum acceptable quality must be 1 to 255\n") ;
  1505.         return 1 ;
  1506.     }
  1507.     
  1508.     Nr_autofloor = val ;
  1509.  
  1510.     return 0 ;
  1511. }
  1512.  
  1513. /* Fixed and now functional, 920317 WG7J */
  1514. int
  1515. donrload(argc,argv,p)
  1516. int argc ;
  1517. char *argv[] ;
  1518. void *p;
  1519. {
  1520.     char buff[255];
  1521.     FILE *fn;
  1522.     time_t now, prev;
  1523.     long t1,t2;
  1524.     int quality,obso,j;
  1525.     int permanent,record;
  1526.     struct iface *ifp;
  1527.     char alias[12],dest[12],iface[12],neighbor[12],type[3],*ptr;
  1528.     char destalias[ALEN+1]; /*alias in 'alias form'*/
  1529.     char destcall[AXALEN];  /*in callsign (ie shifted) form */
  1530.     char destneighbor[AXALEN];
  1531.  
  1532.     if(Nr_iface == NULLIF) {
  1533.         tputs("Attach netrom interface first\n") ;
  1534.         return 1;
  1535.     }
  1536.  
  1537.     if((fn = fopen(Netromfile,READ_TEXT)) == NULLFILE){
  1538. /*
  1539.         tputs("Can't open netrom save file!\n");
  1540. */
  1541.         return 1;
  1542.     }
  1543.  
  1544.     if(fgets(buff,sizeof(buff),fn) == NULLCHAR){ /* read the timestamp */
  1545.         fclose(fn);
  1546.         return 1;
  1547.     }
  1548.     if((strncmp(buff,"time = ",7))!= 0){
  1549. /*
  1550.         tputs("Wrong node file content\n");
  1551. */
  1552.         fclose(fn);
  1553.         return 1;
  1554.     }
  1555.     time(&now);
  1556.     sscanf(buff,"time =%ld",&prev);
  1557. /*
  1558.     tprintf("now = %ld , prev = %ld\n",now,prev);
  1559. */
  1560.     if(prev >= now){
  1561.         /*
  1562.         tputs("You traveled back in time!!\n");
  1563.         */
  1564.         fclose(fn);
  1565.         return 1;
  1566.     }
  1567. #ifdef notdef
  1568.     t1 = now - prev;
  1569.     t2 = dur_timer(&Obsotimer)/1000L;
  1570.     j = t1 / t2;        /* recalculate obsolete count */
  1571.     tprintf("%ld seconds are past ( %d obsolete scans)\n",t1,j);
  1572. #endif
  1573.  
  1574.     while(fgets(buff,sizeof(buff),fn) != NULLCHAR){
  1575.         if((ptr = strchr(buff,':')) == 0){
  1576.             sscanf(buff,"%s%s%i%i%s%s"
  1577.                 ,dest,type,&quality,&obso,iface,neighbor);
  1578.             alias[0] = '\0';
  1579.         } else {    
  1580.             *ptr = ' ';
  1581.             sscanf(buff,"%s%s%s%i%i%s%s"
  1582.                 ,alias,dest,type,&quality,&obso,iface,neighbor);
  1583.         }
  1584.         /*Set and check calls / alias - WG7J */
  1585.         if(setcall(destcall,dest) == -1) {
  1586.             /*
  1587.             tprintf("Bad call %s\n",dest);
  1588.             */
  1589.             continue;
  1590.         }
  1591.         if(setcall(destneighbor,neighbor) == -1) {
  1592.             /*
  1593.             tprintf("Bad call %s\n",neighbor);
  1594.             */
  1595.             continue;
  1596.         }
  1597.         if(putalias(destalias,alias,1) == -1)
  1598.             continue;
  1599.  
  1600.         /* find interface */
  1601.         if((ifp = if_lookup(iface)) == NULLIF)
  1602.             continue;
  1603.  
  1604.         /* Is it a netrom interface ? */
  1605.         if(!(ifp->flags & IS_NR_IFACE))
  1606.             continue;
  1607.  
  1608.         /* get and check quality value */
  1609.         if(quality  > 255 || quality < Nr_autofloor) {
  1610.             /*
  1611.             tprintf("maximum route quality is 255\n") ;
  1612.              */
  1613.              continue;
  1614.         }
  1615.         /* Check the type of route - WG7J */
  1616.         permanent = record = 0;
  1617.         if(strchr(type,'P') != NULLCHAR)
  1618.             permanent = 1;
  1619.         else {
  1620.             if(strchr(type,'R') != NULLCHAR)
  1621.                 record = 1;
  1622.         }
  1623.         nr_routeadd(destalias,destcall,ifp,quality,destneighbor, \
  1624.                     permanent,record) ;
  1625.     }
  1626.     fclose(fn);
  1627.     return 0;
  1628. }
  1629.  
  1630. int
  1631. donrsave(argc,argv,p)
  1632. int argc ;
  1633. char *argv[] ;
  1634. void *p;
  1635. {
  1636.     register struct nrroute_tab *rp ;
  1637.     register struct nr_bind *bp ;
  1638.     register struct nrnbr_tab *np ;
  1639.     char dest[AXALEN] ;
  1640.     char neighbor[AXBUF] ;
  1641.     register int i;
  1642.     char buf[16] ;
  1643.     char *cp ;
  1644.     FILE *fn;
  1645.     time_t now;
  1646.     
  1647. #ifdef __TURBOC__
  1648.     if((fn = fopen(Netromfile,"wt+")) == NULLFILE){
  1649. #else
  1650.     if((fn = fopen(Netromfile,"w+")) == NULLFILE){
  1651. #endif
  1652.         tputs("Can't write netrom save file!\n");
  1653.         return 1;
  1654.     }
  1655.     time(&now);
  1656.     fprintf(fn,"time = %ld\n",now);
  1657.     for(i = 0 ; i < NRNUMCHAINS ; i++){
  1658.         for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next){
  1659.             strcpy(buf,rp->alias) ;
  1660.             /* remove trailing spaces */
  1661.             if((cp = strchr(buf,' ')) == NULLCHAR)
  1662.                 cp = &buf[strlen(buf)] ;
  1663.             if(cp != buf)        /* don't include colon for null alias */
  1664.                 *cp++ = ':' ;
  1665.             for(bp = rp->routes; bp != NULLNRBIND; bp = bp->next) {
  1666.                 pax25(cp,rp->call) ;
  1667.                 fprintf(fn,"%-16s  ",buf) ;
  1668.                 np = bp->via ;
  1669.                 if(fprintf(fn,"%1s %3d  %3d  %-8s  %s\n",
  1670.                       (bp->flags & NRB_PERMANENT ? "P" :
  1671.                       bp->flags & NRB_RECORDED ? "R" : "X"),
  1672.                       bp->quality,bp->obsocnt,
  1673.                       np->iface->name,
  1674.                       pax25(neighbor,np->call)) == EOF)
  1675.                    break;
  1676.             }
  1677.         }
  1678.     }
  1679.     fclose(fn);
  1680.     return 0;
  1681. }
  1682.